package node

import (
	"common/logs"
	"core/remote"
	"encoding/json"
)

type App struct {
	remoteClient   remote.Client
	readChan       chan []byte
	writeChan      chan *remote.Msg
	handlers       LogicHandler
	writeCloseChan chan bool
	readCloseChan  chan bool
}

func Default() *App {
	return &App{
		readChan:       make(chan []byte, 1024),
		writeChan:      make(chan *remote.Msg, 1024),
		handlers:       make(LogicHandler),
		writeCloseChan: make(chan bool),
		readCloseChan:  make(chan bool),
	}
}

func (a *App) Run(serverId string) error {
	a.remoteClient = remote.NewNatsClient(serverId, a.readChan)
	if err := a.remoteClient.Run(); err != nil {
		return err
	}
	go a.readMsg()
	go a.writeMsg()
	return nil
}

// 读取消息并执行 Handler
func (a *App) readMsg() {
	for {
		select {
		case msg := <-a.readChan:
			remoteMsg := new(remote.Msg)
			if err := json.Unmarshal(msg, &remoteMsg); err != nil {
				logs.Error("json 转换异常：%v", err)
			}
			session := remote.NewSession(a.remoteClient, remoteMsg)
			session.SetData(remoteMsg.SessionData)
			// 根据 router 找到对应的 Handler 进行处理
			router := remoteMsg.Router
			if handlerFunc := a.handlers[router]; handlerFunc != nil {
				result := handlerFunc(session, remoteMsg.Body.Data)
				marshal, _ := json.Marshal(result)
				body := remoteMsg.Body
				body.Data = marshal
				// 发送给 connector
				responseMsg := &remote.Msg{
					Src:  remoteMsg.Dst,
					Dst:  remoteMsg.Src,
					Body: body,
					Uid:  remoteMsg.Uid,
					Cid:  remoteMsg.Cid,
				}
				a.writeChan <- responseMsg
			}
		case <-a.readCloseChan:
			return
		}
	}
}

func (a *App) writeMsg() {
	for {
		select {
		case msg, ok := <-a.writeChan:
			if ok {
				marshal, _ := json.Marshal(msg)
				if err := a.remoteClient.SendMsg(msg.Dst, marshal); err != nil {
					logs.Error("app remote 发送失败：%v", err)
				}
			}
		case <-a.writeCloseChan:
			return
		}
	}
}

func (a *App) RegisterHandler(handler LogicHandler) {
	a.handlers = handler
}

func (a *App) Close() {
	if a.remoteClient != nil {
		a.remoteClient.Close()
		close(a.readChan)
		close(a.writeChan)
		a.readCloseChan <- true
		a.writeCloseChan <- true
	}
}
